
#include <iostream>

#define PRO_NAME "tinymmi"

#include "util.hxx"
#include "minilog_static.hxx"

#define AS_SOCKET_SERVER
#include "as_socket.hxx"

/* core lib*/
#include "module.hxx"
#include "modules.hxx"
class AsSocketServer *g_server = nullptr;

void setServer(class AsSocketServer *server)
{
    g_server = server;
}

class AsSocketServer *getServer(void)
{
    return g_server;
}

// echo_parser - 数据检查
static int echo_parser(const char * buf, uint32_t len) {
    return (int)len;
}

static int respondModuleResultsForGetStatusOfAllModulesWithCount(iopbase_t base, uint32_t id, char * data, uint32_t len, struct moduleRespond* resp)
{
    struct socketPackageHead *head;
    int sendLen;
    int ret;
    struct moduleResult *requests;

    if(!resp) return -1;

    /* 解包 */
    head = (struct socketPackageHead *)data;
    sendLen = head->requireLenth;

    requests = (struct moduleResult *)resp->data;

    if(sendLen != resp->size)
    {
        LogE("--> Dismatch send/recv length");
    }

    ret = iop_send(base, id, requests, sendLen);
    delete resp;

    if (ret < SBase) {
        RETURN(ret, "iop_send error id : %u, len = %u, r = %d", id, len, ret);
    }

    return 0;
}

static int respondModuleResult(iopbase_t base, uint32_t id, char * data, uint32_t len, struct moduleRespond* resp)
{
    struct socketPackageHead *head;
    struct moduleRequest *request;
    struct moduleResult moduleResult;
    int sendLen, ret;

    if(!resp) return -1;

    /* 解包 */
    head = (struct socketPackageHead *)data;
    sendLen = head->requireLenth;
    request =(struct moduleRequest*)(head->payload);

    ret = *((int*)resp->data);

    memcpy(moduleResult.name, request->name, MODULE_NAME_MAX_SIZE);
    moduleResult.result = ret;
    ret = iop_send(base, id, &moduleResult, sendLen);
    delete resp;

    if (ret < SBase) {
        RETURN(ret, "iop_send error id : %u, len = %u, r = %d", id, len, ret);
    }
    LogE("--> respondModuleResult length");

    return ret;
}

static int respondModuleResultData(iopbase_t base, uint32_t id, char * data, uint32_t len,
                                   struct moduleRespond* resp)
{
    struct socketPackageHead *head;
    struct moduleRequest *request;
    struct moduleResultData moduleResultData;
    int sendLen, ret;

    if(!resp) return -1;


    /* 解包 */
    head = (struct socketPackageHead *)data;
    sendLen = head->requireLenth;
    request =(struct moduleRequest*)(head->payload);

    memcpy(moduleResultData.name, request->name, MODULE_NAME_MAX_SIZE);
    // 不是每一个模块都有data可以返回的
    if(!request->data)
    {
        LogW(moduleResultData.name, "has not data.");
        memset(moduleResultData.data, 0x00, sizeof(moduleResultData.data));
        moduleResultData.size = 0;
    }else
    {
        memcpy(moduleResultData.data, resp->data,    resp->size);
        moduleResultData.size = resp->size;
    }


    ret = iop_send(base, id, &moduleResultData, sendLen);
    delete resp;

    if (ret < SBase) {
        RETURN(ret, "iop_send error id : %u, len = %u, r = %d", id, len, ret);
    }

    return ret;
}

static int sendRespondStruct(iopbase_t base, uint32_t id, char * data, uint32_t len, struct moduleRespond *resp, int sendLen)
{
    //struct socketPackageHead *head;
    //struct moduleRequest *request;
    if(!resp)
    {
        goto end;
    }

    /* 如果不需要返回结果时，跳过返回处理*/
    if(sendLen <= 0)
    {
        delete resp;
        goto end;
    }

    //head = (struct socketPackageHead *)data;
    //request =(struct moduleRequest*)(head->payload);

    // 回复响应
    switch (resp->type) {
        case RespondTypeModuleResult:
            respondModuleResult(base, id, data, len, resp);
            break;
        case RespondTypeModuleResultData:
            respondModuleResultData(base, id, data, len, resp);
            break;
        case RespondTypeModuleResultsForGetStatusOfAllModulesWithCount:
            respondModuleResultsForGetStatusOfAllModulesWithCount(base, id, data, len, resp);
            break;
        default:
            LogE("unknow type!");
            delete resp;
            goto end;
    }
end:
    return SBase;
}

static int sendRespondString(iopbase_t base, uint32_t id, char * data, uint32_t len, struct moduleRespond *resp)
{
    int ret;
    string respondStr;
    int respReult= TestResultAsPass;

    if(!data)
    {
        goto end;
    }
    if(!resp)
    {
        goto end;
    }

    respondStr = string(data);
    // 回复响应
    switch (resp->type) {
        case RespondTypeModuleResult:
            if(resp->size == sizeof(int))
            {
                respReult = *((int*)resp->data);
            }
            delete resp;
            if(respReult == TestResultAsPass)
                respondStr += " ::OK";
            if(respReult == TestResultAsFail)
                respondStr += " ::ERROR";
            ret = iop_send(base, id, respondStr.c_str(), respondStr.length());
            if (ret < SBase) {
                RETURN(ret, "iop_send error id : %u, len = %u, r = %d", id, len, ret);
            }
            break;
        case RespondTypeModuleResultData:
            respondStr = string((char*)resp->data);
            delete resp;
            ret = iop_send(base, id, respondStr.c_str(), respondStr.length());
            if (ret < SBase) {
                RETURN(ret, "iop_send error id : %u, len = %u, r = %d", id, len, ret);
            }
            break;
        case RespondTypeModuleResultsForGetStatusOfAllModulesWithCount:
            respondStr = string((char*)resp->data);
            delete resp;
            ret = iop_send(base, id, respondStr.c_str(), respondStr.length());
            if (ret < SBase) {
                RETURN(ret, "iop_send error id : %u, len = %u, r = %d", id, len, ret);
            }
            break;
        default:
            LogE("unknow type!");
            delete resp;
            goto end;
    }
end:
    return SBase;
}

// echo_processor - 数据处理
static int echo_processor(iopbase_t base, uint32_t id, char * data, uint32_t len, void * arg) {
    string stringCMD;
    string strChecker = PRO_NAME;
    struct socketPackageHead *head;
    struct moduleRequest *request;
    struct moduleRespond *resp = nullptr;

    /* 解包 */
    head = (struct socketPackageHead *)data;
    request =(struct moduleRequest*)(head->payload);

    /* 判断包是否为 struct 格式*/
    if (request->requestMagic == REQUEST_MAGIC)
    {
        int sendLen;
        LogD("Socket package is struct-format");
        sendLen = head->requireLenth;
        LogD("recv id =", id, "len = ", len, "req =", sendLen);
        // 执行请求
        resp = getServer()->getModluesManager()->handleRequest(request);
        return sendRespondStruct(base, id, data, len, resp, sendLen);
    }

    stringCMD = string(data);
    //要求string以这样子的形式出现： "tinymmi -m run -c demo -v 'hello demo'";
    if(isStringStartsWith(stringCMD, strChecker, 0, strChecker.length()))
    {
        LogD("Socket package is string-format");
        resp = getServer()->getModluesManager()->handleRequest(stringCMD);
        return sendRespondString(base, id, data, len, resp);
    }

    return SBase;
}

// 连接处理
static void echo_connect(iopbase_t base, uint32_t id, void * arg) {
    //printf("echo_connect base = %p, id = %u, arg = %p\n", base, id, arg);
}

// 最终销毁处理
static void echo_destroy(iopbase_t base, uint32_t id, void * arg) {
    //printf("echo_destroy base = %p, id = %u, arg = %p\n", base, id, arg);
}

// 错误处理
static int echo_error(iopbase_t base, uint32_t id, uint32_t events, void * arg) {
    switch (events) {
    case EV_READ:
        CERR("EV_READ    base = %p, id = %u, arg = %p", base, id, arg);
        break;
    case EV_WRITE:
        CERR("EV_WRITE   base = %p, id = %u, arg = %p", base, id, arg);
        break;
    case EV_CREATE:
        CERR("EV_CREATE  base = %p, id = %u, arg = %p", base, id, arg);
        break;
    case EV_TIMEOUT:
        CERR("EV_TIMEOUT base = %p, id = %u, arg = %p", base, id, arg);
        break;
    default:
        CERR("EV_DEFAULT base = %p, id = %u, err = %u, arg = %p", base, id, events, arg);
    }
    return SBase;
}

AsSocketServer::AsSocketServer(void)
{
    m_stop = 1;
    m_base = iops_create(socketGetaddress().c_str(), INT_TIMEOUT,
        echo_parser, echo_processor, echo_connect, echo_destroy, echo_error);
    if(!m_base)
    {
        LogD(__FILE__, __LINE__, "Server create failed", "maybe already has one running.\n");
        exit(EXIT_FAILURE);
    }
    m_runningCB = nullptr;

    m_stop = 0;
    setServer(this);

    LogD(__FILE__, __LINE__, "create a new tcp server host:", socketGetaddress());
    return;
}

AsSocketServer::~AsSocketServer(void)
{
	if(m_base) iops_delete(m_base);
}

void AsSocketServer::setStop(void)
{
    m_stop = 1;
}


void AsSocketServer::addRunningCB(void (*cb)(void*), void* arg)
{
    m_runningCB = cb;
    m_runningArg = arg;
}

int AsSocketServer::exec(void* arg)
{
	unsigned long cnt = 0;
    if(m_stop != 0)
    {
        return 1;
    }
	m_execArg = arg;

    while(m_stop == 0)
    {
        msleep(INT_SLEEP);
        if(m_runningCB != nullptr)
        {
            m_runningCB(m_runningArg);
        }

        cnt ++;
        //LogI(__FILE__, __LINE__, "exec", cnt);
    }
    return 0;
}
